#!/bin/bash

# 数据库备份脚本
set -e

# 配置
BACKUP_DIR="${PWD}/backup"
RETENTION_DAYS=30
LOG_FILE="${PWD}/backup.log"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# 日志函数
log() {
    echo -e "$1" | tee -a "$LOG_FILE"
}

log_info() {
    log "${BLUE}[INFO $(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}

log_success() {
    log "${GREEN}[SUCCESS $(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}

log_error() {
    log "${RED}[ERROR $(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}

# 加载环境变量
load_env() {
    if [ -f ".env.prod" ]; then
        source .env.prod
    else
        log_error "环境文件 .env.prod 不存在"
        exit 1
    fi
}

# 创建备份目录
create_backup_dir() {
    mkdir -p "$BACKUP_DIR"
    mkdir -p "$BACKUP_DIR/daily"
    mkdir -p "$BACKUP_DIR/weekly"
    mkdir -p "$BACKUP_DIR/monthly"
}

# 数据库备份
backup_database() {
    local backup_type=$1
    local timestamp=$(date +%Y%m%d-%H%M%S)
    local backup_file="$BACKUP_DIR/${backup_type}/backup-${backup_type}-${timestamp}.gz"
    
    log_info "开始 ${backup_type} 备份..."
    
    # 创建备份
    docker-compose -f docker-compose.prod.yml exec -T mongodb mongodump \
        --username="${MONGO_ROOT_USERNAME}" \
        --password="${MONGO_ROOT_PASSWORD}" \
        --authenticationDatabase=admin \
        --db="${MONGO_DATABASE}" \
        --gzip \
        --archive > "$backup_file"
    
    if [ $? -eq 0 ]; then
        log_success "${backup_type} 备份完成: $backup_file"
        
        # 验证备份文件
        if [ -s "$backup_file" ]; then
            local file_size=$(stat -f%z "$backup_file" 2>/dev/null || stat -c%s "$backup_file")
            log_info "备份文件大小: $(numfmt --to=iec $file_size)"
        else
            log_error "备份文件为空: $backup_file"
            rm -f "$backup_file"
            exit 1
        fi
    else
        log_error "${backup_type} 备份失败"
        rm -f "$backup_file"
        exit 1
    fi
}

# 备份文件清理
cleanup_old_backups() {
    log_info "清理旧备份文件..."
    
    # 清理日备份（保留30天）
    find "$BACKUP_DIR/daily" -name "backup-daily-*.gz" -mtime +$RETENTION_DAYS -delete 2>/dev/null || true
    
    # 清理周备份（保留12周）
    find "$BACKUP_DIR/weekly" -name "backup-weekly-*.gz" -mtime +84 -delete 2>/dev/null || true
    
    # 清理月备份（保留12个月）
    find "$BACKUP_DIR/monthly" -name "backup-monthly-*.gz" -mtime +365 -delete 2>/dev/null || true
    
    log_success "旧备份清理完成"
}

# 上传备份到远程存储（可选）
upload_backup() {
    local backup_file=$1
    
    if [ -n "$BACKUP_REMOTE_PATH" ] && [ -n "$BACKUP_SSH_KEY" ]; then
        log_info "上传备份到远程存储..."
        
        scp -i "$BACKUP_SSH_KEY" "$backup_file" "$BACKUP_REMOTE_PATH/"
        
        if [ $? -eq 0 ]; then
            log_success "备份已上传到远程存储"
        else
            log_error "远程上传失败"
        fi
    fi
}

# 备份验证
verify_backup() {
    local backup_file=$1
    
    log_info "验证备份文件..."
    
    # 测试备份文件完整性
    if docker-compose -f docker-compose.prod.yml exec -T mongodb mongorestore \
        --username="${MONGO_ROOT_USERNAME}" \
        --password="${MONGO_ROOT_PASSWORD}" \
        --authenticationDatabase=admin \
        --dryRun \
        --gzip \
        --archive < "$backup_file" &> /dev/null; then
        log_success "备份文件验证通过"
    else
        log_error "备份文件验证失败"
        exit 1
    fi
}

# 发送通知
send_notification() {
    local status=$1
    local message=$2
    
    if [ -n "$MONITOR_EMAIL" ] && command -v mail &> /dev/null; then
        echo "$message" | mail -s "数据库备份通知 - $status" "$MONITOR_EMAIL"
    fi
    
    # Webhook通知（可选）
    if [ -n "$WEBHOOK_URL" ]; then
        curl -X POST "$WEBHOOK_URL" \
            -H "Content-Type: application/json" \
            -d "{\"text\":\"$message\"}" &> /dev/null || true
    fi
}

# 主备份函数
main() {
    local backup_type=${1:-daily}
    
    log_info "开始数据库备份 (类型: $backup_type)..."
    
    # 加载环境变量
    load_env
    
    # 创建备份目录
    create_backup_dir
    
    # 检查Docker服务状态
    if ! docker-compose -f docker-compose.prod.yml ps mongodb | grep -q "Up"; then
        log_error "MongoDB 服务未运行"
        send_notification "失败" "MongoDB 服务未运行，备份取消"
        exit 1
    fi
    
    # 执行备份
    local timestamp=$(date +%Y%m%d-%H%M%S)
    local backup_file="$BACKUP_DIR/${backup_type}/backup-${backup_type}-${timestamp}.gz"
    
    backup_database "$backup_type"
    
    # 验证备份
    verify_backup "$backup_file"
    
    # 上传备份（如果配置了）
    upload_backup "$backup_file"
    
    # 清理旧备份
    cleanup_old_backups
    
    log_success "备份流程完成"
    send_notification "成功" "数据库 ${backup_type} 备份完成: $backup_file"
}

# 恢复函数
restore() {
    local backup_file=$1
    
    if [ -z "$backup_file" ]; then
        log_error "请指定备份文件"
        echo "用法: $0 restore <backup_file>"
        exit 1
    fi
    
    if [ ! -f "$backup_file" ]; then
        log_error "备份文件不存在: $backup_file"
        exit 1
    fi
    
    log_info "从备份恢复数据库: $backup_file"
    
    # 确认操作
    read -p "此操作将覆盖现有数据库，是否继续? [y/N]: " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        log_info "恢复操作已取消"
        exit 0
    fi
    
    # 加载环境变量
    load_env
    
    # 执行恢复
    docker-compose -f docker-compose.prod.yml exec -T mongodb mongorestore \
        --username="${MONGO_ROOT_USERNAME}" \
        --password="${MONGO_ROOT_PASSWORD}" \
        --authenticationDatabase=admin \
        --drop \
        --gzip \
        --archive < "$backup_file"
    
    if [ $? -eq 0 ]; then
        log_success "数据库恢复完成"
    else
        log_error "数据库恢复失败"
        exit 1
    fi
}

# 显示帮助
show_help() {
    echo "数据库备份脚本"
    echo ""
    echo "用法: $0 [command] [options]"
    echo ""
    echo "命令:"
    echo "  daily           创建日备份 (默认)"
    echo "  weekly          创建周备份"
    echo "  monthly         创建月备份"
    echo "  restore <file>  从指定备份文件恢复"
    echo "  list            列出所有备份文件"
    echo "  cleanup         手动清理旧备份"
    echo "  help            显示此帮助信息"
    echo ""
    echo "示例:"
    echo "  $0 daily        # 创建日备份"
    echo "  $0 restore backup/daily/backup-daily-20250722-120000.gz"
}

# 列出备份文件
list_backups() {
    log_info "备份文件列表:"
    
    for type in daily weekly monthly; do
        echo ""
        echo "${type} 备份:"
        if [ -d "$BACKUP_DIR/$type" ]; then
            ls -lh "$BACKUP_DIR/$type/"backup-*.gz 2>/dev/null || echo "  无备份文件"
        else
            echo "  目录不存在"
        fi
    done
}

# 主程序
case "${1:-daily}" in
    daily|weekly|monthly)
        main "$1"
        ;;
    restore)
        restore "$2"
        ;;
    list)
        list_backups
        ;;
    cleanup)
        load_env
        cleanup_old_backups
        ;;
    help|--help|-h)
        show_help
        ;;
    *)
        log_error "未知命令: $1"
        show_help
        exit 1
        ;;
esac